package com.sghd.football.module.game.service.core;

import com.sghd.football.module.game.service.config.AbstractTemplete;
import com.sghd.football.module.game.service.model.Result;

import java.util.*;

/**
 * \* Created with 王创辉.
 * \* Date: 2018/5/18
 * \* Time: 14:38
 * \* @desc: 棋盘
 */
public class ChessBoard {
    /** 列*/
    private int col;
    /** 行*/
    private int row;
    /** 棋格*/
    private Grid[] grids;

    public static ChessBoard valueOf(int row, int col) {
        ChessBoard chessBoard = new ChessBoard();
        chessBoard.col = col;
        chessBoard.row = row;
        chessBoard.grids = new Grid[row * col];
        for (int i = 0; i < chessBoard.grids.length; i++) {
            chessBoard.grids[i] = new Grid();
        }
        return chessBoard;
    }

    /**
     * @param free 是否是免费旋转
     * @return 游戏结果
     */
    public Result operator(int roomId, boolean free, int baseBet) {
        Map<Integer, Integer> scatter2Count = new HashMap<>();//每列的scater个数
        Map<Integer, Integer> bounds2Coutn = new HashMap<>();//每列的bouns个数
        Collection<ChessType> ignore = new HashSet<>();//随机取元素时会被忽略的(不会被取出来的)
        //随机棋盘
        AbstractTemplete.lock.readLock().lock();//上读锁
        try {
            for (int i = 0; i < grids.length; i++) {
                //同一列不能出现两个相同的特殊元素（CT_SCATTER, CT_BONUS）
                int zcol = i / row + 1;//当前列
                int scats = scatter2Count.get(zcol) == null ? 0 : scatter2Count.get(zcol);//当前列scater个数
                int bouns = bounds2Coutn.get(zcol) == null ? 0 : bounds2Coutn.get(zcol);//当前列bouns个数
                ignore.clear();//清空上一个棋子的信息
                if (!Rule.oneThreeFive.contains(zcol)) {//scatter只能出现在1.3.5列
                    ignore.add(ChessType.CT_SCATTER);
                }
                if (scats >= 1 || bouns >= 1) {//每列只能有一个特殊元素
                    ignore.addAll(Arrays.asList(ChessType.CT_SCATTER, ChessType.CT_BONUS));
                }
                //免费中不会再中免费(免费旋转时：当前棋盘中已经有两个scatter了，不会再生成scatter)
                if (free && !ignore.contains(ChessType.CT_SCATTER) &&
                        scatter2Count.values().stream().reduce(0, Integer::sum) == 2) {
                    ignore.add(ChessType.CT_SCATTER);
                }
                //Grid grid = Grid.valueOf(ChessType.getChess(free, roomId, ignore));
                //计数
                ChessType chessType = ChessType.getChess(free, roomId, ignore);
                if (chessType == ChessType.CT_SCATTER) {
                    scatter2Count.put(zcol, scats + 1);
                }
                if (chessType == ChessType.CT_BONUS) {
                    bounds2Coutn.put(zcol, bouns + 1);
                }
                grids[i].update(chessType);
            }
        } catch (Exception e) {
            throw e;
        } finally {
            AbstractTemplete.lock.readLock().unlock();
        }
        return Rule.calc(this.grids, row).calc(baseBet).setCurrentFree(free);
    }

    //test
    public static void main(String[] args) {
        ChessBoard chessBoard = ChessBoard.valueOf(3, 5);
        for (int i = 0; i < 10000; i++) {
            chessBoard.operator(0, false, 1000);
            chessBoard.print();
            Result result = chessBoard.result();
            result.print();
            System.out.println("--------------------------------");
            System.out.println();
            System.out.println();
            System.out.println();
        }

    }

    /**
     * 打印
     */
    public void print() {
        for (int i = 0; i < row; i++) {
            for (int j = 0; j < col; j++) {
                int index = i + j * row;
                try {
                    Grid grid = grids[index];
                    ChessType chess = grid.getChess();
                    System.out.print(chess + "\t");
                } catch (Exception e) {
                    System.out.print("Empty_" + "\t");
                }
            }
            System.out.println();
        }
    }

    public Result result() {
        return Rule.calc(this.grids, row);
    }

    public int getCol() {
        return col;
    }

    public void setCol(int col) {
        this.col = col;
    }

    public int getRow() {
        return row;
    }

    public void setRow(int row) {
        this.row = row;
    }

    public Grid[] getGrids() {
        return grids;
    }

    public void setGrids(Grid[] grids) {
        this.grids = grids;
    }

}
